-- 自举
local function bootstrap()
	-- 设置操作系统的路径分隔符 os.dirsep, C语言扩展模块的文件扩展名 os.cmodext
	local _, _, dirsep, cmodext = package.cpath:find("%.([\\/])?.(%w+);");
	os.dirsep, os.cmodext = dirsep, cmodext;
	-- 取得trunk路径(即当前运行的脚本文件路径,有可能是相对路径)，并保存到 os.trunkPath
	local path = string.sub(debug.getinfo(2).source, 2);
	os.trunkPath = string.match(path, "^(.*)" .. os.dirsep);
	-- 把trunk路径添加到包查找路径最前面
	package.path = string.format("%s%s?.lua;%s", os.trunkPath, os.dirsep, package.path);
	package.cpath = string.format("%s%s?.%s;%s", os.trunkPath, os.dirsep, os.cmodext, package.cpath);
end
bootstrap();

-- 加载包要放到自举之后，否则有可能因为路径问题找不到包
local zylib = require("zylib")
local lfs = require("lfs")

local function parseConfigFile(filepath)
	local macroTable = {};
	local file, err = io.open(filepath, "r");
	if (file == nil) then error(err); end
	
	while true do
		local defconfig = file:read("*l");
		if defconfig == nil then break; end
		
		-- 去掉注释行
		defconfig = defconfig:gsub("^#.*$", "");
		-- 去掉头部空白
		defconfig = defconfig:gsub("^%s+", "");
		-- 去掉尾部空白
		defconfig = defconfig:gsub("%s+$", "");
		
		-- 处理非空行
		if #defconfig > 0 then
			-- 去掉=号两边的空白
			defconfig = defconfig:gsub("%s*=%s*", "=");
			-- 把 =y 改成 =1
			defconfig = defconfig:gsub("=y$", "=1");
			-- 取得 name = value
			local ps, pe, name, value = defconfig:find("^([^=]+)=(.*)$");
			if name ~= nil and value ~= nil then
				-- 去掉值两边的引号
				value = value:gsub('"', "");
				-- 保存到符号表
				macroTable[name] = value;
				print(name, value)
			end
		end
	end
	
	file:close();
	return macroTable;
end

local function fillMacros(language, macroTable)
	for name, value in pairs(macroTable) do
		local macro = language:append("macro");
		macro:append("name")[1] = name;
		macro:append("value")[1] = value;
	end
end

-- 搜索目录为 include/inc 的目录
local function searchHeaderDirs(root, dirs)
	dirs = dirs or {};
	
    for file in lfs.dir(root) do
        if file ~= "." and file ~= ".." then
            local path = root .. os.dirsep .. file
            local attr = lfs.attributes(path)
            assert(type(attr) == "table")
            if attr.mode == "directory" then
				if file == "include" or file == "inc" then
					table.insert(dirs, path);
					print(path);
				else
					searchHeaderDirs(path, dirs);
				end
            end
        end
    end
	
	return dirs;
end

local function fillIncludes(language, dirs)
	for i, dir in ipairs(dirs) do
		-- 相对目录换成工程目录
		dir = dir:gsub("^%.", "${ProjDirPath}");
		-- 目录分隔符标准化
		dir = dir:gsub("[/\\]", os.dirsep);
		language:append("includepath")[1] = dir;
	end
end

local function writeXml(dirs, macroTable, xmlPath)
	local ok, err = require("LuaXML");
	local LuaXML = xml;
	if not ok or LuaXML == nil then error("No LuaXML support !"); end
	
	local xml = LuaXML.new("cdtprojectproperties");
	
	local section = xml:append("section"); section.name = "org.eclipse.cdt.internal.ui.wizards.settingswizards.IncludePaths";	
	local language;
	language = section:append("language"); language.name = "Assembly";
	fillIncludes(language, dirs);
	language = section:append("language"); language.name = "GNU C++";
	fillIncludes(language, dirs);
	language = section:append("language"); language.name = "GNU C";
	fillIncludes(language, dirs);
	
	local section = xml:append("section"); section.name = "org.eclipse.cdt.internal.ui.wizards.settingswizards.Macros";	
	local language;
	language = section:append("language"); language.name = "Assembly";
	fillMacros(language, macroTable);
	language = section:append("language"); language.name = "GNU C++";
	fillMacros(language, macroTable);
	language = section:append("language"); language.name = "GNU C";
	fillMacros(language, macroTable);

	xml:save(xmlPath);
end

-- 主程序入口
local function main(argc, argv)
	if argc < 3 then
		print(
[[
error: missing parameters !

usage: lua defconfig2xml.lua projRootPath defconfigPath eclipseEnvXmlPath
eg: lua defconfig2xml.lua . defconfig .env/sdk.xml
]]
		);
		return;
	end
	
	local dirs = {
		"C:\\cygwin\\opt\\gcc-arm-none-eabi\\lib\\gcc\\arm-none-eabi\\8.2.1\\include",
		"C:\\cygwin\\opt\\gcc-arm-none-eabi\\arm-none-eabi\\include",
	};
	searchHeaderDirs(argv[1], dirs);
	local macroTable = parseConfigFile(argv[2]);
	writeXml(dirs, macroTable, argv[3]);
end

-- 进入主程序入口
main(#arg, arg);
